package com.shallowUniverse.process.utils;

import com.shallowUniverse.process.annotation.ProcessEntry;
import com.shallowUniverse.process.entity.Approval;
import com.shallowUniverse.process.entity.ApprovalDetails;
import com.shallowUniverse.process.entity.ProcessNodeDefinition;
import com.shallowUniverse.process.exception.ApprovalNotExistException;
import com.shallowUniverse.process.exception.PrimaryKeyNotFoundException;
import com.shallowUniverse.process.mapper.ApprovalDetailsMapper;
import com.shallowUniverse.process.service.ProcessNodeDefinitionService;
import com.shallowUniverse.process.service.ApprovalService;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author gs
 * @date create in 2021/1/7 11:19
 */
public class ProcessUtil {

    /**
     * description: 检查是否符合条件 <br/>
     * author: gs   <br/>
     * date: 2021/1/7 <br/>
     * params: [approval, processNodeDefinition, processNodeDefinitionService, approvalService] <br/>
     * return: boolean
     */
    public static boolean validate(Approval approval, ProcessNodeDefinition processNodeDefinition, ProcessNodeDefinitionService processNodeDefinitionService, ApprovalService approvalService) {
        //拿到目标表
        String target = approval.getTarget();
        //拿到目标表主键
        String targetId = approval.getPrimaryKey();
        //拿到目标表主键值
        String id = approval.getTargetId();
        //拿到需要查的字段
        String field = processNodeDefinition.getField();
        //拿到符号
        String sign = processNodeDefinition.getSign();
        //拿到节点中的值
        Double count = processNodeDefinition.getCount();
        //判断符号、count和field是否为空
        if (ObjectUtils.isEmpty(field) || ObjectUtils.isEmpty(sign) || count == null || count == 0) {
            return false;
        }
        //组织到map中
        Map<String, String> params = new HashMap<>(4);
        params.put("target", target);
        params.put("targetId", targetId);
        params.put("id", id);
        params.put("field", field);
        //查询出数据
        String result = processNodeDefinitionService.findFieldValue(params);
        //转换
        double value = Double.parseDouble(result);
        //判断符号
        switch (sign) {
            case Constant.GREAT_EQUALS:
                return value >= count;
            case Constant.GREAT:
                return value > count;
            case Constant.LESS_EQUALS:
                return value <= count;
            default:
                return value < count;
        }
    }

    /**
     * description: 解析ProcessEntry拿到主键值 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/7/29 <br/>
     * params: [method, args] <br/>
     * return: java.util.Map<java.lang.String,java.lang.Object> <br/>
     * version: 1.0
     */
    public static Map<Constant, Object> parseProcessEntry(Method method, Object[] args) throws PrimaryKeyNotFoundException {
        ProcessEntry processEntry = null;
        int index = -1;
        //获取方法参数注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (int j = 0; j < parameterAnnotations[i].length; j++) {
                //判断是否是ProcessEntry注解
                if (parameterAnnotations[i][j].annotationType() == ProcessEntry.class) {
                    processEntry = (ProcessEntry) parameterAnnotations[i][j];
                    index = i;
                }
            }
        }
        //判断是否取到了注解
        if (ObjectUtils.isEmpty(processEntry)) {
            return null;
        }
        //拿到注解对应的参数
        Object entry = args[index];
        //拿到主键字段名
        String primaryKey = processEntry.primaryKey();
        //拿到流程字段名
        String processField = processEntry.processField();
        //设置参数值
        Map<Constant, Object> params = new HashMap<>(2);
        params.put(Constant.PRIMARY_KEY, ProcessUtil.getFieldValue(entry, primaryKey));
        params.put(Constant.PROCESS_FIELD, ProcessUtil.getFieldValue(entry, processField));
        params.put(Constant.PRIMARY_KEY_FIELD, primaryKey);
        params.put(Constant.UNDERSCORE_TO_CAMEL_CASE, processEntry.underscoreToCamelCase());
        //返回参数
        return params;
    }

    /**
     * description: 拼接节点id <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/7/26 <br/>
     * params: [processNodeDefinitions] <br/>
     * return: java.lang.String <br/>
     * version: 1.0
     */
    public static String joinProcessNodeDefinition(List<ProcessNodeDefinition> processNodeDefinitions) {
        return processNodeDefinitions
                .stream()
                .map(processNodeDefinition -> String.valueOf(processNodeDefinition.getId()))
                .collect(Collectors.joining(","));
    }

    /**
     * description: 拿到字段值 <br/>
     * author: gs   <br/>
     * date: 2020/12/18 <br/>
     * params: [type, fieldName] <br/>
     * return: java.lang.Object
     */
    public static Object getFieldValue(Object entry, String fieldName) {
        //拿到对象的类型
        Class type = entry.getClass();
        Field field = FieldUtils.getDeclaredField(type, fieldName, true);
        if (!ObjectUtils.isEmpty(field)) {
            try {
                return FieldUtils.readField(entry, fieldName, true);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * description: 设置当前节点名称和目标表数据 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/7/28 <br/>
     * params: [approvals, processNodeDefinitionService] <br/>
     * return: void <br/>
     * version: 1.0
     */
    public static void populateProcessNodeAndTarget(List<Approval> approvals, ProcessNodeDefinitionService processNodeDefinitionService, ApprovalService approvalService) {
        //查询所有节点
        List<ProcessNodeDefinition> processNodeDefinitions = processNodeDefinitionService.find(null);
        //设置节点中文
        approvals.forEach(approval -> {
            try {
                //设置目标表数据
                approval.setTargetData(approvalService.findTableData(approval.getId()));
            } catch (ApprovalNotExistException e) {
                e.printStackTrace();
            }
            //拆分当前节点
            List<Long> nodes = Arrays.stream(approval.getCurrent().split(",")).map(Long::parseLong).collect(Collectors.toList());
            //设置节点名
            approval.setCurrentNode(
                    processNodeDefinitions.stream()
                            .filter(processNodeDefinition -> nodes.contains(processNodeDefinition.getId()))
                            .map(ProcessNodeDefinition::getName)
                            .collect(Collectors.joining(","))
            );
        });
    }

    /**
     * description: 设置审批节点名称 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/7/28 <br/>
     * params: [approvalDetailsList, processNodeDefinitionService] <br/>
     * return: void <br/>
     * version: 1.0
     */
    public static void populateProcessNodeAndTarget(List<ApprovalDetails> approvalDetailsList, ProcessNodeDefinitionService processNodeDefinitionService) {
        //查询所有节点
        List<ProcessNodeDefinition> processNodeDefinitions = processNodeDefinitionService.find(null);
        //设置节点中文
        approvalDetailsList.forEach(approvalDetails -> {
            //拆分当前节点
            List<Long> nodes = Arrays.stream(approvalDetails.getProcessNodeId().split(",")).map(Long::parseLong).collect(Collectors.toList());
            //设置节点名
            approvalDetails.setProcessNodeName(
                    processNodeDefinitions.stream()
                            .filter(processNodeDefinition -> nodes.contains(processNodeDefinition.getId()))
                            .map(ProcessNodeDefinition::getName)
                            .collect(Collectors.joining(","))
            );
        });
    }

    /**
     * description: 集合转换为逗号分隔 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/7/28 <br/>
     * params: [data] <br/>
     * return: java.lang.String <br/>
     * version: 1.0
     */
    public static <T> String parseCollectionToString(List<T> data) {
        return data.stream().map(String::valueOf).collect(Collectors.joining(","));
    }

    /**
     * description: 判断是否全部通过的方法 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/8/16 <br/>
     * params: [processNodeDefinitionService, approvalDetailsMapper, approval, currentNode] <br/>
     * return: boolean <br/>
     * version: 1.0
     */
    public static boolean ifAllAllowed(ProcessNodeDefinitionService processNodeDefinitionService, ApprovalDetailsMapper approvalDetailsMapper, Approval approval, ProcessNodeDefinition currentNode) {
        //判断当前顺序节点是否已经全部通过
        //查找当前审批流顺序所有节点
        ProcessNodeDefinition processNode =
                Builder.of(ProcessNodeDefinition::new)
                        .with(ProcessNodeDefinition::setProcessId, approval.getProcessId())
                        .with(ProcessNodeDefinition::setSeq, currentNode.getSeq())
                        .build();
        List<ProcessNodeDefinition> currentNodeList = processNodeDefinitionService.find(processNode);
        //查找详情
        ApprovalDetails details =
                Builder.of(ApprovalDetails::new)
                        .with(ApprovalDetails::setApprovalId, approval.getId())
                        .with(ApprovalDetails::setInfo, Constant.AUDIT_ALLOW_SIGN)
                        .build();
        List<ApprovalDetails> allowDetails = approvalDetailsMapper.selectList(details);
        //返回结果
        AtomicBoolean flag = new AtomicBoolean(true);
        //判断详情是否和当前节点全部匹配
        if (!CollectionUtils.isEmpty(allowDetails)) {
            List<Long> processNodeIds = allowDetails.stream().map(ApprovalDetails::getProcessNodeId).map(Long::parseLong).collect(Collectors.toList());
            currentNodeList.forEach(processNodeDefinition -> {
                if (!processNodeIds.contains(processNodeDefinition.getId())) {
                    flag.set(false);
                }
            });
        } else {
            flag.set(false);
        }
        return flag.get();
    }

    /**
     * description: 移除一个节点 <br/>
     * author: Shuai Guo   <br/>
     * date: 2021/8/16 <br/>
     * params: [current, currentNodeId] <br/>
     * return: java.lang.String <br/>
     * version: 1.0
     */
    public static String removeNode(String current, Long currentNodeId) {
        List<String> ids = Arrays.stream(current.split(",")).collect(Collectors.toList());
        ids.remove(String.valueOf(currentNodeId));
        return String.join(",",ids);
    }
}
